package com.feilong.modules.service.order.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.feilong.modules.client.auth.AuthClient;
import com.feilong.modules.common.exception.APIException;
import com.feilong.modules.common.request.WxOperateDbRequest;
import com.feilong.modules.common.utils.SingletonSnowFlake;
import com.feilong.modules.dao.order.OrderInfoDao;
import com.feilong.modules.model.order.constant.OrderInfoConstant;
import com.feilong.modules.model.order.enums.OrderStateEnum;
import com.feilong.modules.model.order.po.OrderInfoPO;
import com.feilong.modules.model.order.request.AddOrderRequest;
import com.feilong.modules.model.order.request.OrderInfoRequest;
import com.feilong.modules.model.order.request.UpdateOrderRequest;
import com.feilong.modules.model.order.vo.OrderDetailVO;
import com.feilong.modules.model.order.vo.OrderInfoVO;
import com.feilong.modules.service.order.OrderDetailService;
import com.feilong.modules.service.order.OrderInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoDao,OrderInfoPO> implements OrderInfoService {

    @Value("${feilongshop.config.appid}")
    private String APPID;

    @Value("${feilongshop.config.app-secret}")
    private String APPSECRET;

    @Value("${feilongshop.config.env}")
    private String ENV;

    public static final String CONTRACT_DATE_TIME_FORMAT = "yyyyMMddHHmmss";

    // 获取订单号自增数的key
    public static final String ORDER_NUM_KEY = "feilongOrderNumber";

    // 订单编号后缀自动补0
    public static final String NUMBER_PATTERN = "00000";

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private OrderDetailService orderDetailService;

    @Resource
    private AuthClient authClient;

    /**
     * 从云开发服务器获取订单列表信息
     * @param query
     * @return
     */
    @Override
    public Page<OrderInfoVO> getOrderInfo(OrderInfoRequest query) {
        Page<OrderInfoVO> page = new Page<>();
        // 默认每页10条记录
        Integer pageSize = Optional.ofNullable(query.getSize()).orElse(10);
        // 默认为第一页
        Integer currentPage = Optional.ofNullable(query.getCurrent()).orElse(1);
        // 设置偏移量 (页数-1)*每页记录数
        Integer skip = (currentPage - 1) * pageSize;
        // 获取AccessToken
        String token = getAccessToken();
        WxOperateDbRequest request = new WxOperateDbRequest();
        request.setEnv(ENV);
        // 判断查询方式，并根据时间倒序查询
        if (StringUtils.isNotBlank(query.getOrderID())) {
            request.setQuery("db.collection(\"order\").where({orderID:\"" + query.getOrderID() + "\"})" +
                    ".orderBy('time', 'desc').limit(" + pageSize + ").skip(" + skip + ").get()");
        } else if (StringUtils.isNotBlank(query.getContactName())) {
            request.setQuery("db.collection(\"order\").where({contactName:\"" + query.getContactName() + "\"})" +
                    ".orderBy('time', 'desc').limit(" + pageSize + ").skip(" + skip + ").get()");
        } else if (StringUtils.isNotBlank(query.getState())) {
            request.setQuery("db.collection(\"order\").where({state:\"" + query.getState() + "\"})" +
                    ".orderBy('time', 'desc').limit(" + pageSize + ").skip(" + skip + ").get()");
        } else {
            request.setQuery("db.collection(\"order\").orderBy('time', 'desc').limit(" + pageSize + ").skip(" + skip + ").get()");
        }
        String result = authClient.queryCloudDbInfo(request, token);
        page = getOrderListPage(result, page);
        page.setCurrent(currentPage);
        page.setSize(pageSize);
        return page;
    }

    /**
     * 根据订单编号获取云开发服务器订单详情
     * @param orderId
     * @return
     */
    @Override
    public OrderDetailVO getOrderDetail(String orderId) {
        // 获取AccessToken
        String token = getAccessToken();
        WxOperateDbRequest request = new WxOperateDbRequest();
        request.setEnv(ENV);
        request.setQuery("db.collection(\"order\").where({orderID:\"" + orderId + "\"}).get()");
        String result = authClient.queryCloudDbInfo(request, token);
        if (StringUtils.isBlank(result)) {
            throw new APIException(OrderInfoConstant.ORDER_DETAIL_UNEXIST);
        }
        // 返回的数据中的data里包含 \ 字符，去掉才能方便取值
        //result = StringEscapeUtils.unescapeJava(result);
        // 需要获取数据中的data:["{...}"]大括号和大括号里面的值
        return getOrderDetailData(result);
    }

    /**
     * 新增订单信息
     * @param orderInfo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrderInfo(AddOrderRequest orderInfo) {
        Date createTime = new Date();
        // 生成订单号
        String orderNumber = createOrderNumber();
        orderInfo.getOrderInfo().setOrderNumber(orderNumber);
        orderInfo.getOrderInfo().setState(OrderStateEnum.WAIT_DELIVER.getCode());
        orderInfo.getOrderInfo().setCreateTime(createTime);
        // 生成18位雪花id作为订单id
        Long id = SingletonSnowFlake.generateId();
        orderInfo.getOrderInfo().setId(id);
        // 添加主表信息
        this.save(orderInfo.getOrderInfo());
        // 添加订单详情表信息
        orderInfo.getOrderDetail().forEach(item -> {
            item.setOrderId(id);
            item.setCreateTime(createTime);
        });
        orderDetailService.saveBatch(orderInfo.getOrderDetail());
    }

    /**
     * 删除云开发数据库订单信息
     * @param orderID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delOrder(String orderID) {
        // 获取AccessToken
        String token = getAccessToken();
        WxOperateDbRequest request = new WxOperateDbRequest();
        request.setEnv(ENV);
        request.setQuery("db.collection(\"order\").where({orderID:\"" + orderID + "\"}).remove()");
        String result = authClient.deleteCloudDbInfo(request, token);
        JSONObject jsonObject = JSONObject.parseObject(result);
        if (jsonObject.getIntValue("errcode") != 0) {
            // 错误码不为0，删除失败
            throw new APIException(OrderInfoConstant.DELETE_ORDER_ERROR);
        }
    }

    /**
     * 更新云开发数据库订单信息
     * @param request
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrder(UpdateOrderRequest request) {
        // 获取AccessToken
        String token = getAccessToken();
        WxOperateDbRequest updateRequest = new WxOperateDbRequest();
        updateRequest.setEnv(ENV);
        updateRequest.setQuery("db.collection(\"order\").where({orderID:\"" + request.getOrderID() + "\"}).update({" +
                "data: {" +
                "state:\"" + request.getState() + "\"," +
                "contactName:\"" + request.getContactName() + "\"," +
                "address:\"" + request.getAddress() + "\"," +
                "phone:\"" + request.getPhone() + "\"," +
                "logistics:\"" + request.getLogistics() + "\"," +
                "logisticsID:\"" + request.getLogisticsId() + "\"}})"
        );
        String result = authClient.updateCloudDbInfo(updateRequest, token);
        log.info("更新云开发数据库订单信息，更新结果： {}", result);
    }

    /**
     * 生成订单编号
     * 编号格式：年月日时分秒+五位数的自增数，从00001开始
     * @return
     */
    public String createOrderNumber(){
        // 获取年月日时分秒
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(CONTRACT_DATE_TIME_FORMAT);
        String prefix = dateTimeFormatter.format(now);
        // 获取自增数
        Integer number = (Integer) redisTemplate.opsForValue().get(ORDER_NUM_KEY);
        if (number == null) {
            // 设置过期时间为1分钟，初始值为1
            redisTemplate.opsForValue().set(ORDER_NUM_KEY,1,1, TimeUnit.MINUTES);
            number = 1;
        }
        redisTemplate.opsForValue().increment(ORDER_NUM_KEY);
        // 自增数补0
        DecimalFormat decimalFormat = new DecimalFormat();
        decimalFormat.applyPattern(NUMBER_PATTERN);
        String suffix = decimalFormat.format(number);
        return prefix + suffix;
    }

    /**
     * 针对微信订单详情返回值的特殊处理
     * @param result
     */
    private OrderDetailVO getOrderDetailData(String result) {
        OrderDetailVO orderDetailVO = new OrderDetailVO();
        //找到第一个 [" 后面的 { 和最后一个 "] 前面的 } 并截取
//        int firstIndex = result.indexOf("[") + 2;
//        int lastIndex = result.lastIndexOf("]") - 1;
        JSONArray data = JSON.parseObject(result).getJSONArray("data");
        if (data.size() != 1) {
            throw new APIException(OrderInfoConstant.ORDER_DETAIL_UNEXIST);
        }
        JSONObject jsonObject = JSONObject.parseObject(data.getString(0));
        //JSONObject jsonObject = JSONObject.parseObject(result.substring(firstIndex, lastIndex));
        orderDetailVO = jsonObject.toJavaObject(OrderDetailVO.class);
        return orderDetailVO;
    }

    /**
     * 针对微信订单列表返回值的特殊处理
     * @param result
     * @param page
     * @return
     */
    private Page<OrderInfoVO> getOrderListPage(String result, Page page) {
        List<OrderInfoVO> list = new ArrayList<>();
        JSONObject resultObject = JSON.parseObject(result);
        // 先取出data
        JSONArray data = resultObject.getJSONArray("data");
        if (data.size() != 0) {
            // 转换为list
            data.forEach(item ->{
                JSONObject jsonObject = JSONObject.parseObject(item.toString());
                OrderInfoVO orderInfo = jsonObject.toJavaObject(OrderInfoVO.class);
                list.add(orderInfo);
            });
        }
        // 获取记录总数
        JSONObject pager = resultObject.getJSONObject("pager");
        page.setRecords(list);
        page.setTotal(pager.getIntValue("Total"));
        return page;
    }

    /**
     * 获取小程序AccessToken
     * @return
     */
    public String getAccessToken(){
        String result = authClient.getAccessToken(APPID,APPSECRET);
        JSONObject data = JSONObject.parseObject(result);
        String token = data.getString("access_token");
        log.info("获取到的微信云开发AccessToken为 -> {}", token);
        return token;
    }
}
